package top.gbyun.engine.processor;

import akka.actor.ActorContext;
import akka.actor.ActorRef;
import akka.actor.PoisonPill;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import top.gbyun.core.ActorSystemContext;
import top.gbyun.core.entity.FlowInfo;
import top.gbyun.core.entity.NodeInfo;
import top.gbyun.core.msg.EngineMsg;
import top.gbyun.core.msg.NodeToFlowTellNextMsg;
import top.gbyun.engine.actor.NodeActor;
import top.gbyun.core.enmus.ComponentLifecycleState;

import java.util.*;

/**
 * @author gengbin
 * @date 2024-12-25-14:53
 */
@Slf4j
public class FlowActorMsgProcessor extends ComponentMsgProcessor{

    private final FlowInfo flowInfo;

    private final Map<String, List<ActorRef>> nodeActorRouter;

    private final Map<String, ActorRef> nodeActorMap;

    private boolean started;

    public FlowActorMsgProcessor(FlowInfo flowInfo,ActorSystemContext systemContext) {
        super(systemContext,flowInfo.getId());
        this.flowInfo = flowInfo;
        this.nodeActorRouter = new HashMap<>();
        this.nodeActorMap = new HashMap<>();
    }

    /**
     * 流程启动
     * @author gengbin
     * @date 2024/12/25 15:01
     * @return void
     */
    @Override
    public void start(ActorContext context) throws Exception {
        log.info("[{}] Going to start actors of Rule", flowId);
        if (!started) {
            //1.创建子节点
            //ActorRef start = getContext().actorOf(NodeActor.props(nodeMap.get("start")));
            for (NodeInfo nodeInfo : flowInfo.getNodeMap().values()){
                ActorRef actorRef = context.actorOf(NodeActor.props(systemContext,nodeInfo,flowInfo), nodeInfo.getId());
                nodeActorMap.put(nodeInfo.getId(), actorRef);
            }
            initRoutes();
            log.info("节点表:{}",nodeActorMap.toString());
            started = true;
        }else{
            onUpdate(context);
        }


    }

    private void initRoutes() {
        for (NodeInfo nodeInfo : flowInfo.getNodeMap().values()){
            if(nodeInfo.getTo()!=null&& !nodeInfo.getTo().isEmpty()){
                for (String toNodeId:nodeInfo.getTo()) {
                    ActorRef actorRef = nodeActorMap.get(toNodeId);
                    if(actorRef==null){
                        log.error("构建节点路由出现异常");
                        throw new IllegalArgumentException("Node [" + nodeInfo.getId() + "] has invalid relation to Rule node [" + nodeInfo.getTo() + "]");
                    }
                    nodeActorRouter.computeIfAbsent(nodeInfo.getId(), k -> new ArrayList<>())
                            .add(actorRef);
                }
            }else{
                nodeActorRouter.put(nodeInfo.getId(), Collections.emptyList());
            }
        }
        log.info("节点路由表:{}",nodeActorRouter.toString());
        log.info("流程[{}-{}]已经启动", flowInfo.getId(), flowInfo.getName());

        state = ComponentLifecycleState.ACTIVE;
    }

    /**
     * 流程停止
     * @author gengbin
     * @date 2024/12/25 15:02
     * @return void
     */
    @Override
    public void stop(ActorContext context) throws Exception {
        log.trace("[{}][{}] Stopping rule chain with {} nodes", flowId, nodeActorMap.size());
        for (String nodeId : nodeActorMap.keySet()) {
            nodeActorMap.get(nodeId).tell(PoisonPill.getInstance(), ActorRef.noSender());
        }
        nodeActorMap.clear();
        nodeActorRouter.clear();
        started = false;
    }


    @Override
    public void onCreated(ActorContext context) throws Exception {
        start(context);
    }

    @Override
    public void onUpdate(ActorContext context) throws Exception {
        restart(context);
    }

    @Override
    public void onActivate(ActorContext context) throws Exception {
        restart(context);
    }

    @Override
    public void onSuspend(ActorContext context) throws Exception {
        stop(context);
    }

    @Override
    public void onStop(ActorContext context) throws Exception {
        stop(context);
    }

    public void onNodeToFlowTellNextMsg(ActorContext ctx,NodeToFlowTellNextMsg msg) {
        log.info("流程[{}]收到节点[{}]路由消息",msg.getMsg().getFlowId(),msg.getMsg().getNodeId());
        List<ActorRef> actorRefs = nodeActorRouter.get(msg.getNodeId());
        if(actorRefs!=null&&!actorRefs.isEmpty()){
            for (ActorRef actorRef : actorRefs){
                EngineMsg engineMsg = new EngineMsg(UUID.randomUUID(), msg.getMsg().getFlowId(), msg.getMsg().getNodeId(), System.currentTimeMillis(), new JSONObject());
                actorRef.tell(engineMsg, ctx.self());
            }
        }
    }

    public void test(ActorContext ct){
        ActorRef nodeb01 = nodeActorMap.get("nodea01");
        nodeb01.tell(new EngineMsg(UUID.randomUUID(), "flow01", "nodea01", System.currentTimeMillis(), new JSONObject()), ct.self());
    }
}
